use std::rc::Rc;
use std::cell::Cell;

pub struct TOBMuxRegister(Rc<Cell<Option<usize>>>);

impl TOBMuxRegister {
    pub fn new(val: usize) -> Self {
        Self(Rc::new(Cell::new(Some(val))))
    }

    pub fn empty() -> Self {
        Self(Rc::new(Cell::new(None)))
    }
}

impl TOBMuxRegister {
    pub fn get(&self) -> Option<usize> {
        self.0.get()
    }

    pub fn set(&self, val: usize) {
        self.0.set(Some(val))
    }

    pub fn reset(&self) {
        self.0.set(None);
    }
}

impl TOBMuxRegister {
    pub fn rc_clone(&self) -> Self {
        Self(self.0.clone())
    }
}

impl Clone for TOBMuxRegister {
    fn clone(&self) -> Self {
        Self(Rc::new(Cell::new(self.get())))
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_clone() {
        let reg1 = TOBMuxRegister::new(0);
        let reg2 = reg1.clone();

        reg1.set(1);
        assert_eq!(reg2.get(), Some(0));

        reg2.set(10);
        assert_eq!(reg1.get(), Some(1));
    
        assert_ne!(reg1.0.as_ptr(), reg2.0.as_ptr());
    }

    #[test]
    fn test_rc_clone() {
        let reg1 = TOBMuxRegister::new(0);
        let reg2 = reg1.rc_clone();

        reg1.set(1);
        assert_eq!(reg2.get(), Some(1));

        reg2.set(10);
        assert_eq!(reg1.get(), Some(10));
    
        assert_eq!(reg1.0.as_ptr(), reg2.0.as_ptr());
    }
}